using Precise.Products;

using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using Abp.Linq.Extensions;
using System.Collections.Generic;
using System.Threading.Tasks;
using Abp.Domain.Repositories;
using Precise.Products.Exporting;
using Precise.Products.Dtos;
using Precise.Dto;
using Abp.Application.Services.Dto;
using Precise.Authorization;
using Abp.Extensions;
using Abp.Authorization;
using Microsoft.EntityFrameworkCore;

namespace Precise.Products
{
	[AbpAuthorize(AppPermissions.Pages_Goods)]
    public class GoodsAppService : PreciseAppServiceBase, IGoodsAppService
    {
		 private readonly IRepository<Goods, long> _goodsRepository;
		 private readonly IGoodsExcelExporter _goodsExcelExporter;
		 private readonly IRepository<Product,long> _productRepository;
		 

		  public GoodsAppService(IRepository<Goods, long> goodsRepository, IGoodsExcelExporter goodsExcelExporter , IRepository<Product, long> productRepository) 
		  {
			_goodsRepository = goodsRepository;
			_goodsExcelExporter = goodsExcelExporter;
			_productRepository = productRepository;
		
		  }

		 public async Task<PagedResultDto<GetGoodsForView>> GetAll(GetAllGoodsInput input)
         {
			
			var filteredGoods = _goodsRepository.GetAll()
						.WhereIf(!string.IsNullOrWhiteSpace(input.Filter), e => false  || e.Name.Contains(input.Filter) || e.Description.Contains(input.Filter))
						.WhereIf(!string.IsNullOrWhiteSpace(input.Name),  e => e.Name.ToLower() == input.Name.ToLower().Trim())
						.WhereIf(input.MinTotalNumber != null, e => e.TotalNumber >= input.MinTotalNumber)
						.WhereIf(input.MaxTotalNumber != null, e => e.TotalNumber <= input.MaxTotalNumber)
						.WhereIf(input.MinPrice != null, e => e.Price >= input.MinPrice)
						.WhereIf(input.MaxPrice != null, e => e.Price <= input.MaxPrice)
						.WhereIf(!string.IsNullOrWhiteSpace(input.Description),  e => e.Description.ToLower() == input.Description.ToLower().Trim());


			var query = (from o in filteredGoods
                         join o1 in _productRepository.GetAll() on o.ProductId equals o1.Id into j1
                         from s1 in j1.DefaultIfEmpty()
                         
                         select new GetGoodsForView() {
							Goods = ObjectMapper.Map<GoodsDto>(o),
                         	ProductName = s1 == null ? "" : s1.Name.ToString()
						})
						.WhereIf(!string.IsNullOrWhiteSpace(input.ProductName), e => e.ProductName.ToLower() == input.ProductName.ToLower().Trim());

            var totalCount = await query.CountAsync();

            var goods = await query
                .OrderBy(input.Sorting ?? "goods.id asc")
                .PageBy(input)
                .ToListAsync();

            return new PagedResultDto<GetGoodsForView>(
                totalCount,
                goods
            );
         }
		 
		 [AbpAuthorize(AppPermissions.Pages_Goods_Edit)]
		 public async Task<GetGoodsForEditOutput> GetGoodsForEdit(EntityDto<long> input)
         {
            var goods = await _goodsRepository.FirstOrDefaultAsync(input.Id);
           
		    var output = new GetGoodsForEditOutput {Goods = ObjectMapper.Map<CreateOrEditGoodsDto>(goods)};

		    if (output.Goods.ProductId != null)
            {
                var product = await _productRepository.FirstOrDefaultAsync((long)output.Goods.ProductId);
                output.ProductName = product.Name.ToString();
            }
			
            return output;
         }

		 public async Task CreateOrEdit(CreateOrEditGoodsDto input)
         {
            if(input.Id == null){
				await Create(input);
			}
			else{
				await Update(input);
			}
         }

		 [AbpAuthorize(AppPermissions.Pages_Goods_Create)]
		 private async Task Create(CreateOrEditGoodsDto input)
         {
            var goods = ObjectMapper.Map<Goods>(input);

			
			if (AbpSession.TenantId != null)
			{
				goods.TenantId = (int) AbpSession.TenantId;
			}
		

            await _goodsRepository.InsertAsync(goods);
         }

		 [AbpAuthorize(AppPermissions.Pages_Goods_Edit)]
		 private async Task Update(CreateOrEditGoodsDto input)
         {
            var goods = await _goodsRepository.FirstOrDefaultAsync((long)input.Id);
             ObjectMapper.Map(input, goods);
         }

		 [AbpAuthorize(AppPermissions.Pages_Goods_Delete)]
         public async Task Delete(EntityDto<long> input)
         {
            await _goodsRepository.DeleteAsync(input.Id);
         } 

		public async Task<FileDto> GetGoodsToExcel(GetAllGoodsForExcelInput input)
         {
			
			var filteredGoods = _goodsRepository.GetAll()
						.WhereIf(!string.IsNullOrWhiteSpace(input.Filter), e => false  || e.Name.Contains(input.Filter) || e.Description.Contains(input.Filter))
						.WhereIf(!string.IsNullOrWhiteSpace(input.Name),  e => e.Name.ToLower() == input.Name.ToLower().Trim())
						.WhereIf(input.MinTotalNumber != null, e => e.TotalNumber >= input.MinTotalNumber)
						.WhereIf(input.MaxTotalNumber != null, e => e.TotalNumber <= input.MaxTotalNumber)
						.WhereIf(input.MinPrice != null, e => e.Price >= input.MinPrice)
						.WhereIf(input.MaxPrice != null, e => e.Price <= input.MaxPrice)
						.WhereIf(!string.IsNullOrWhiteSpace(input.Description),  e => e.Description.ToLower() == input.Description.ToLower().Trim());


			var query = (from o in filteredGoods
                         join o1 in _productRepository.GetAll() on o.ProductId equals o1.Id into j1
                         from s1 in j1.DefaultIfEmpty()
                         
                         select new GetGoodsForView() { 
							Goods = ObjectMapper.Map<GoodsDto>(o),
                         	ProductName = s1 == null ? "" : s1.Name.ToString()
						 })
						.WhereIf(!string.IsNullOrWhiteSpace(input.ProductName), e => e.ProductName.ToLower() == input.ProductName.ToLower().Trim());


            var goodsListDtos = await query.ToListAsync();

            return _goodsExcelExporter.ExportToFile(goodsListDtos);
         }



		[AbpAuthorize(AppPermissions.Pages_Goods)]
         public async Task<PagedResultDto<ProductLookupTableDto>> GetAllProductForLookupTable(GetAllForLookupTableInput input)
         {
             var query = _productRepository.GetAll().WhereIf(
                    !string.IsNullOrWhiteSpace(input.Filter),
                   e=> e.Name.ToString().Contains(input.Filter)
                );

            var totalCount = await query.CountAsync();

            var productList = await query
                .PageBy(input)
                .ToListAsync();

			var lookupTableDtoList = new List<ProductLookupTableDto>();
			foreach(var product in productList){
				lookupTableDtoList.Add(new ProductLookupTableDto
				{
					Id = product.Id,
					DisplayName = product.Name?.ToString()
				});
			}

            return new PagedResultDto<ProductLookupTableDto>(
                totalCount,
                lookupTableDtoList
            );
         }
    }
}